package com.smedi.ismedi.organization.core.application.service.impl;

import cn.hutool.db.Entity;
import com.smedi.ismedi.authority.starter.util.VerifyHelper;
import com.smedi.ismedi.constructionproject.api.dto.response.resp.ProjectAssignmentResp;
import com.smedi.ismedi.constructionproject.api.dto.response.resp.ProjectResp;
import com.smedi.ismedi.organization.core.application.command.*;
import com.smedi.ismedi.organization.core.application.service.HrOrgManageApplicationService;
import com.smedi.ismedi.organization.core.domain.aggregatemodel.HrOrganization;
import com.smedi.ismedi.organization.core.domain.aggregatemodel.SendMessage;
import com.smedi.ismedi.organization.core.domain.aggregatemodel.dto.OrganizationAssignmentQuery;
import com.smedi.ismedi.organization.core.domain.aggregatemodel.dto.OrganizationQuery;
import com.smedi.ismedi.organization.core.domain.aggregatemodel.dto.PersonQuery;
import com.smedi.ismedi.organization.core.domain.aggregatemodel.model.Organization;
import com.smedi.ismedi.organization.core.domain.aggregatemodel.model.OrganizationAssignment;
import com.smedi.ismedi.organization.core.domain.aggregatemodel.model.Person;
import com.smedi.ismedi.organization.core.domain.repository.HrOrganizationRepository;
import com.smedi.ismedi.organization.core.domain.service.HrOrganizationDomainService;
import com.smedi.ismedi.organization.core.infrastructure.constant.CustomError;
import com.smedi.ismedi.organization.core.port.adapter.persistence.dto.ProjectAssignmentQuery;
import com.smedi.ismedi.organization.core.port.adapter.persistence.dto.ProjectQuery;
import com.smedi.ismedi.organization.core.port.adapter.service.ConstructionProjectRemoteApiService;
import com.smedi.ismedi.organization.core.port.adapter.service.MessageRemoteService;
import com.smedi.ismedi.organization.core.port.adapter.service.PersonnelRemoteApiService;
import com.smedi.ismedi.web.starter.exception.LogicException;
import com.smedi.ismedi.web.starter.util.DozerUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

import static com.smedi.ismedi.organization.core.infrastructure.constant.ConstantField.SMS_TEMPLATE_ORG_NOTIFICATION;
import static com.smedi.ismedi.organization.core.infrastructure.constant.ConstantField.SMS_TEMPLATE_PROJECT_NOTIFICATION;
import static com.smedi.ismedi.organization.core.infrastructure.enumerate.HrOrganizationTypeEnum.PROJECT_MANAGEMENT_ORGANIZATION;

@Slf4j
@Service
@RequiredArgsConstructor
public class HrOrgManageApplicationServiceImpl implements HrOrgManageApplicationService {
    private final HrOrganizationDomainService hrOrganizationDomainService;

    private final HrOrganizationRepository hrOrganizationRepository;

    private final PersonnelRemoteApiService personnelRemoteApiService;

    private final DozerUtil dozerUtil;

    private final MessageRemoteService messageRemoteService;

    private final ConstructionProjectRemoteApiService constructionProjectRemoteApiService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public HrOrganization saveHrOrganization(HrOrganizationCommand hrOrganizationCommand) {
        HrOrganization hrOrganization = dozerUtil.convertor(hrOrganizationCommand, HrOrganization.class);
        return hrOrganizationDomainService.save(hrOrganization);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteHrOrganization(Long orgId) {
        hrOrganizationDomainService.delete(orgId);
    }

    @Override
    public Boolean checkHrOrganizationIsAvailable(Long orgId) {
        return hrOrganizationDomainService.validateHrOrganization(orgId);
    }

    @Override
    public Boolean checkHrOrganizationCanHasProjectAvailable(Long orgId) {
        return hrOrganizationDomainService.validateHrOrganizationCanHasProject(orgId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void exchangeTwoHrOrganizationNodeSort(HrOrganizationCommand hrOrganizationCommandPartOne, HrOrganizationCommand hrOrganizationCommandPartTwo) {
        if (hrOrganizationCommandPartOne == null || hrOrganizationCommandPartTwo == null) {
            throw LogicException.raise(CustomError.EXCHANGE_NODE_MISS_ONE_NODE);
        }

        hrOrganizationDomainService.saveHrOrganizationDisplayOrder(hrOrganizationCommandPartOne.getHrOrganizationId(), hrOrganizationCommandPartOne.getDisplayOrder());

        hrOrganizationDomainService.saveHrOrganizationDisplayOrder(hrOrganizationCommandPartTwo.getHrOrganizationId(), hrOrganizationCommandPartTwo.getDisplayOrder());
    }

    @Override
    public long updateHrOrgByShortName(HrOrgUpdateCommand hrOrgUpdateCommand) {

        return hrOrganizationDomainService.updateHrOrgByShortName(hrOrgUpdateCommand.getShortName(), hrOrgUpdateCommand.getDingDeptKey());
    }

    @Override
    public SendMessage sendMessageByRoleNotExists(SendMessageByRoleCommand sendMessageByRoleCommand) {
        List<Organization> organizations = hrOrganizationRepository.getOrganizationListWithoutToken(OrganizationQuery.builder()
                .build());
        List<String> orgNames = new ArrayList<>();
        String mobile = "";
        Set<Long> organizationIdSet = new HashSet<>();
        Map<Long, Organization> organizationMap = new HashMap<>();
        StringBuilder shortName = new StringBuilder();
        if (VerifyHelper.isAvailable(organizations)) {
            for (Organization organization : organizations) {
                if (PROJECT_MANAGEMENT_ORGANIZATION.getValue().equals(organization.getType())) {
                    organizationIdSet.add(organization.getId());
                    organizationMap.put(organization.getId(), organization);
                }

            }

            List<Person> operatorPersons = personnelRemoteApiService.getPersonList(PersonQuery.builder().isDelete(false).nameLike(sendMessageByRoleCommand.getReceiverName()).build());
            if (VerifyHelper.isAvailable(operatorPersons)) {
                mobile = operatorPersons.get(0).getMobile();
                if (VerifyHelper.isAvailable(organizationIdSet)) {
                    List<Person> personList = personnelRemoteApiService.getPersonList(PersonQuery.builder().isDelete(false)
                            .organizationIds(new ArrayList<>(organizationIdSet))
                            .roleName(sendMessageByRoleCommand.getCheckRoleName())
                            .build());

                    List<Long> personIds = personList.stream().map(Person::getId).collect(Collectors.toList());

                    List<OrganizationAssignment> personAssignments = personnelRemoteApiService.getOrganizationAssignmentListWithoutToken(OrganizationAssignmentQuery.builder()
                            .personIds(personIds)
                            .organizationIds(new ArrayList<>(organizationIdSet))
                            .build());

                    if (VerifyHelper.isAvailable(personAssignments)) {
                        for (OrganizationAssignment organizationAssignment : personAssignments) {
                            organizationMap.remove(organizationAssignment.getHrOrganizationId());
                        }
                    }


                    if (VerifyHelper.isAvailable(organizationMap)) {
                        for (Organization entry : organizationMap.values()) {
                            shortName.append("【");
                            if (VerifyHelper.isNull(entry.getShortName())) {
                                shortName.append(entry.getFullName());
                                orgNames.add(entry.getFullName());
                            } else {
                                shortName.append(entry.getShortName());
                                orgNames.add(entry.getShortName());
                            }

                            shortName.append("】 ");
                        }
                        messageRemoteService.sendMessage(MessageSendCommand.builder()
                                .smsTemplateName(SMS_TEMPLATE_ORG_NOTIFICATION)
                                .mobiles(new ArrayList<>(Collections.singletonList(mobile)))
                                .parameters(new ArrayList<>(Arrays.asList(shortName.toString(), sendMessageByRoleCommand.getCheckRoleName(), sendMessageByRoleCommand.getDeadline())))
                                .build());
                    }


                }
            }
        }
        return SendMessage.builder()
                .receiverName(sendMessageByRoleCommand.getReceiverName())
                .orgNames(orgNames)
                .deadline(sendMessageByRoleCommand.getDeadline())
                .mobile(mobile)
                .build();

    }

    @Override
    public List<SendMessage> sendMessageByJobNotExists(SendMessageByJobCommand sendMessageByJobCommand) {
        //获取有项目的组织
        List<SendMessage> sendMessages = new ArrayList<>();
        List<Organization> organizations = hrOrganizationRepository.getOrganizationListWithoutToken(OrganizationQuery.builder()
                .type(PROJECT_MANAGEMENT_ORGANIZATION.getValue())
                .build());
        Set<Long> organizationIdSet = new HashSet<>();
        Map<Long, Organization> organizationMap = new HashMap<>();
        if (VerifyHelper.isAvailable(organizations)) {
            for (Organization organization : organizations) {
                if (PROJECT_MANAGEMENT_ORGANIZATION.getValue().equals(organization.getType())) {
                    organizationIdSet.add(organization.getId());
                    organizationMap.put(organization.getId(), organization);
                }
            }

            //查询未开工、建设中、停工的项目
            List<ProjectResp> projectList = constructionProjectRemoteApiService.getProjectListWithoutToken(ProjectQuery.builder()
                    .hrOrganizationIds(new ArrayList<>(organizationIdSet))
                    .projectStatuses(new ArrayList<>(Arrays.asList("NOT_STARTED", "CONSTRUCTING", "STOPPED")))
                    .build());

            if (VerifyHelper.isAvailable(projectList)) {
                List<Long> projectIds = new ArrayList<>();
                Map<Long, Long> projectOrgMap = new HashMap<>();
                Map<Long, ProjectResp> projectRespMap = new HashMap<>();
                projectList.forEach(projectResp -> {
                    projectIds.add(projectResp.getId());
                    projectOrgMap.put(projectResp.getId(), projectResp.getHrOrganizationId());
                    projectRespMap.put(projectResp.getId(), projectResp);
                });

                //获取这些项目中的特定的职务分配情况
                List<ProjectAssignmentResp> projectAssignments = constructionProjectRemoteApiService.getProjectAssignmentList(ProjectAssignmentQuery.builder()
                        .projectIds(projectIds)
                        .projectJobs(sendMessageByJobCommand.getCheckJobNames())
                        .build());

                Map<Long, Long> countMap = new HashMap<>();
                Set<String> checkProjectSet = new HashSet<>();
                if (VerifyHelper.isAvailable(projectAssignments)) {
                    projectAssignments.forEach(projectAssignmentResp -> {
                        Long projectId = projectAssignmentResp.getProjectId();
                        String projectJob = projectAssignmentResp.getProjectJob();
                        if (checkProjectSet.add(projectId + projectJob)) {
                            Long count = countMap.getOrDefault(projectId, 0L);
                            count++;
                            countMap.put(projectId, count);
                        }
                    });
                }
                Set<Long> sendProjectSet = new HashSet<>(projectIds);
                for (Map.Entry<Long, Long> entry : countMap.entrySet()) {
                    if (entry.getValue() >= sendMessageByJobCommand.getCheckJobNames().size()) {
                        sendProjectSet.remove(entry.getKey());
                    }
                }
                //获取需要发短信的项目，分类统计到组织下
                Map<Long, Set<Long>> orgProjectMap = new HashMap<>();
                Set<Long> sendOrgId = new HashSet<>();
                for (Long projectId : sendProjectSet) {
                    Long orgId = projectOrgMap.get(projectId);
                    sendOrgId.add(orgId);
                    Set<Long> projectIdSet = orgProjectMap.getOrDefault(orgId, new HashSet<>());
                    projectIdSet.add(projectId);
                    orgProjectMap.put(orgId, projectIdSet);
                }

                //获取对应组织的短信接收人信息
                List<Person> personList = personnelRemoteApiService.getPersonList(PersonQuery.builder().isDelete(false)
                        .organizationIds(new ArrayList<>(sendOrgId))
                        .roleNames(sendMessageByJobCommand.getReceiverRoles())
                        .build());

                if (VerifyHelper.isAvailable(personList)) {
                    Set<Long> personIdSet = new HashSet<>();
                    Map<Long, Person> personMap = new HashMap<>();
                    for (Person person : personList) {
                        personIdSet.add(person.getId());
                        personMap.put(person.getId(), person);
                    }
                    //获取接收人和组织的分配关系
                    List<OrganizationAssignment> personAssignments = personnelRemoteApiService.getOrganizationAssignmentListWithoutToken(OrganizationAssignmentQuery.builder()
                            .personIds(new ArrayList<>(personIdSet))
                            .organizationIds(new ArrayList<>(sendOrgId))
                            .build());

                    Set<String> checkOrgSet = new HashSet<>();
                    if (VerifyHelper.isAvailable(personAssignments)) {
                        for (OrganizationAssignment organizationAssignment : personAssignments) {
                            Long personId = organizationAssignment.getPersonId();
                            Long orgId = organizationAssignment.getHrOrganizationId();
                            //过滤，同一个人一个组织只发一次
                            if (checkOrgSet.add(personId + String.valueOf(orgId))) {
                                Organization organization = organizationMap.get(orgId);
                                StringBuilder proName = new StringBuilder();
                                String orgName = "【" + (null != organization.getShortName() ? organization.getShortName() : organization.getFullName()) + "】 ";

                                Set<Long> tempSet = orgProjectMap.get(orgId);
                                List<String> projectNames = new ArrayList<>();
                                if (VerifyHelper.isAvailable(tempSet)) {
                                    for (Long id : orgProjectMap.get(orgId)) {
                                        String name = null != projectRespMap.get(id).getProjectShortName() ? projectRespMap.get(id).getProjectShortName() : projectRespMap.get(id).getProjectName();
                                        projectNames.add(name);
                                        proName.append("【");
                                        proName.append(name);
                                        proName.append("】 ");
                                    }
                                    String jobs = sendMessageByJobCommand.getCheckJobNames().stream().collect(Collectors.joining("、"));
                                    messageRemoteService.sendMessage(MessageSendCommand.builder()
                                            .smsTemplateName(SMS_TEMPLATE_PROJECT_NOTIFICATION)
                                            .mobiles(new ArrayList<>(Collections.singletonList(personMap.get(personId).getMobile())))
                                            .parameters(new ArrayList<>(Arrays.asList(orgName, proName.toString(), String.valueOf(tempSet.size()), jobs, sendMessageByJobCommand.getDeadline())))
                                            .build());
                                    sendMessages.add(SendMessage.builder().orgName(orgName).projectNames(projectNames).receiverName(personMap.get(personId).getName()).mobile(personMap.get(personId).getMobile()).build());
                                }
                            }
                        }
                    }
                }

            }


        }
        return sendMessages;
    }
}
